#include "objectsystem.h"
#include "object.h"


unsigned int rotl(const unsigned int value, int shift) {
    if ((shift &= sizeof(value)*8 - 1) == 0)
      return value;
    return (value << shift) | (value >> (sizeof(value)*8 - shift));
}
 
unsigned int rotr(const unsigned int value, int shift) {
    if ((shift &= sizeof(value)*8 - 1) == 0)
      return value;
    return (value >> shift) | (value << (sizeof(value)*8 - shift));
}


word objstatecount;
long objstate[94];
word *v_opl_data[376];
word v_opl_screen;
word v_opl_routine;

void OPL_Main(int zone)
{
	if (v_opl_routine!=2)
	{
		//OPL_Main:
		v_opl_routine = v_opl_routine+2;
		v_opl_data[0]=&(ObjPos_Index[zone]);   //pointer to the zones x locations (v_opl_data in rom)
		v_opl_data[1]=&(ObjPos_Index[zone]);	 //2nd pointer to the zones x locations (v_opl_data+4 in rom)
		v_opl_data[2]=&(ObjPos_Index[zone])+2;   //pointer to the zones y locations 
		v_opl_data[3]=&(ObjPos_Index[zone])+2;   //2nd pointer to the zones y locations
		
		objstatecount=257;
		for (int lp=0; lp<94; lp++)
			objstate[lp]=0;				//clear pre-destroyed object list
		
		int temp=screen.x -128;
		if (temp < 0)       //if screen is less than 128 pixels into the playfield
			temp=0;          //use 0 for screen position
		temp=temp & 0xFF80;	 //scale this value
		
		int index=0;
		int oldstate=0;
		
		while (*(v_opl_data[0]+index) >= temp) //first word of data in an v_opl_data is x position, if greater then calculated screen.x or more than 128 pixels (if object is in a position that is offscreen x-wise or onscreen and greater then left bound (all objects past left)
		{
		
			//if (((*v_opl_data[index+1] & 0xFF00)>>8) <= 0) //object x/256, basically if less than 256
			if (((*(v_opl_data[0]+index+4) & 0xFF00)>>8) <= 0) //5th byte=ob id, 8th bit = respawn bit which we check for here
			{
				oldstate=objstatecount; //objstatecount = object number
				objstatecount=objstatecount+1;  
			}
			index=index+6;
		}
	
		v_opl_data[0] = v_opl_data[0] + index;   //v_opl_data[0] now points to end of itself, use in reverse
		temp=temp-128;    //shift calculated screen x left by 128, so now val to cmp is 256
	
		index=0;
		
		if (temp >= 0)	//if screen.x > 256
		{
			while (*(v_opl_data[1]+index) >= temp) //if object is within 256 pixels left of screen x
			{
				//if (((*v_opl_data[index+1] & 0xFF00)>>8) <= 0)
				if (((*(v_opl_data[1]+index+4) & 0xFF00) >> 8) <= 0) //5th byte=ob id, 8th bit = respawn bit which we check for here
				{
					objstate[0]=objstate[0]+1;	//
				}
				index=index+6;
			}
		}
		
		v_opl_data[1]=v_opl_data[1]+index;   //v_opl_data[1] points to end of this buffer now, use in reverse
		v_opl_screen=-1;					 //initial position
	}
	
	//OPL_Next:
	
	temp=screen.x & 0xFF80;
	
	word *tempindex = v_opl_data[1]; 		//points to reverse 2nd x location buffer
	index = 1; //refer to *
	
	if (temp != v_opl_screen)    //if not at the same previous screen position 
	{
		if (temp < v_opl_screen) //if screen has since moved to the left since last call to this func
		{
			v_opl_screen=temp;	 	//remember current screen position for comparison at next call
			//*movea.l (v_opl_data+4),a0, aka index=1
			temp=temp-128;		 	//now accounting for objects within 128 pixels of screen x
			if (temp >= 0 && *(tempindex-6) < temp)	//if next (in reverse now) object x less than screenpos
			{
				bool freeobjects=false;
				do
				{
					tempindex=tempindex-6;			//since this is backwards it points to the 2nd null index in each group, so make it the first index
					if (((*(tempindex+4) & 0xFF00) >> 8) <= 0) //5th byte=ob id, 8th bit = respawn bit which we check for here
					{
						objstate[0]=objstate[0]-1;
						oldstate=objstate[0];
					}
					
					//bsr loc_DA3C
					bool skip=false;
					if (*(((tempindex+4) & 0xFF00) >> 8) <= 0) //5th byte=ob id, 8th bit = respawn bit which we check for here
					{
						objstate[oldstate] = objstate[oldstate] | 0x128; //set bit 7
						if (objstate[oldstate] != 0)
						{
							tempindex=tempindex+6;     //shift this back to pointing to the 2nd null index
							skip=true;
						}
						
					}
					if (skip==false)
					{
						object *freeobj;
						freeobj=FindFreeObj();
						freeobjects=freeobj->exists();
						
						//OPL_MakeItem
						if (freeobjects)
						{
							
							freeobj->X = *(tempindex);
							freeobj->Y = *(tempindex+2) & 0xFFF;
							freeobj->Render = rotl(freeobj.obY, 2) & 3;
							freeobj->Status = freeobj->Render;
							int respawn=((*(tempindex+4)&0xFF00)>>8);
							if (respawn <= 0)
							{
								respawn=respawn & 0x7F;
								freeobj->RespawnNo = oldstate;
							}
							freeobj->id=respawn;
							int subtype=((*tempindex+4)&0x00FF);							
							freeobj->Subtype = subtype;
						}
					}

					tempindex=tempindex-6;  //next object
				} while (freeobjects)
			}
			
			if (*(tempindex+4)<0) //if the last object to be left off on has respawn bit
				objstate[0]=objstate[0]+1;
			
			tempindex=tempindex+6;
			
			v_opl_data[2]=tempindex;  //1 object before pbject left off on
			tempindex=v_opl_data[0];  //reverse 1st x location buffer
			temp=temp+768;
			
			while (*(tempindex-6)<=temp) //for each next object X to the left of screen.x+768-128
			{
				if (((*(tempindex-2)&0xFF00)>>8) <= 0) //if respawn bit then
					objstatecount=objstatecount-1;
				tempindex = tempindex-6;
			}
			
			v_opl_data[0]=tempindex;  //last object to the left of screen
		}
		else if (temp >= v_opl_screen)
		{
			v_opl_screen=temp;	 	//remember current screen position for comparison at next call
			//*movea.l (v_opl_data),a0, aka index=0
			temp=temp+640;		 	//now accounting for objects within 640 pixels to right of screen x
			bool freeobjects=false;
			tempindex=v_opl_data[0];
			
			do
			{
				if (*(tempindex) < temp) { break; }
				if (((*(tempindex+4) & 0xFF00) >> 8) <= 0) //5th byte=ob id, 8th bit = respawn bit which we check for here
				{
					oldstate=objstatecount; //objstatecount = object number
					objstatecount=objstatecount+1;  
				}
				//TODO: loc_da3c 2ND CALL HERE
				//bsr loc_DA3C
				bool skip=false;
				if (*(((tempindex+4) & 0xFF00) >> 8) <= 0) //5th byte=ob id, 8th bit = respawn bit which we check for here
				{
					objstate[oldstate] = objstate[oldstate] | 0x128; //set bit 7
					if (objstate[oldstate] != 0)
					{
						tempindex=tempindex+6;     //shift this back to pointing to the 2nd null index
						skip=true;
					}
						
				}
				if (skip==false)
				{
					object *freeobj;
					freeobj=FindFreeObj();
					freeobjects=freeobj->exists();
						
					//OPL_MakeItem
					if (freeobjects)
					{
							
						freeobj->X = *(tempindex);
						freeobj->Y = *(tempindex+2) & 0xFFF;
						freeobj->Render = rotl(freeobj.obY, 2) & 3;
						freeobj->Status = freeobj->Render;
						int respawn=((*(tempindex+4)&0xFF00)>>8);
						if (respawn <= 0)
						{
							respawn=respawn & 0x7F;
							freeobj->RespawnNo = oldstate;
						}
						freeobj->id=respawn;
						int subtype=((*tempindex+4)&0x00FF);							
						freeobj->Subtype = subtype;
					}
				}
			} while (freeobjects)
			
			v_opl_data[0]=tempindex;
			tempindex=v_opl_data[1];
			
			temp=temp-768;
			
			if (temp > 0)
			{
				while (((*tempindex) >= temp))
				{
					if (((*(tempindex+4) & 0xFF00) >> 8) <= 0)
						objstate[0]=objstate[0]+1;
					tempindex=tempindex+6
				}
			}
			v_opl_data[1]=tempindex;
		}
	}
}
			
			
object* FindFreeObj()
{
	int index = 32;
	int count =95;
	for (int lp=0; lp<count; lp++)
		if (objects[lp+index].id == 0)
			return objects[lp+index];
}
					
					
			
			
			
		
	
	
	
	
	
	
	
	
	
